package api_service

import (
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/services/devstar_ssh_key_pair/errors"
	"code.gitea.io/gitea/services/devstar_ssh_key_pair/vo"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"golang.org/x/crypto/ssh"
	"strconv"
)

// GenerateNewRSASSHSessionKeyPair 生成 RSA SSH 密钥对
func GenerateNewRSASSHSessionKeyPair() (error, *vo.GenerateNewRSASSHSessionKeyPairVO) {

	// 1. 生成 SSH 密钥对 （算法 RSA，长度 setting.Devstar.SSHKeypair.KeySize）
	privateKey, err := rsa.GenerateKey(rand.Reader, setting.Devstar.SSHKeypair.KeySize)
	if err != nil {
		return err, nil
	}

	// 2. 获取 Private Key PEM
	privateKeyDer := x509.MarshalPKCS1PrivateKey(privateKey)
	privateKeyBlock := pem.Block{
		Type:    "RSA PRIVATE KEY",
		Headers: nil,
		Bytes:   privateKeyDer,
	}
	privateKeyPem := pem.EncodeToMemory(&privateKeyBlock)
	if privateKeyPem == nil {
		return errors.ErrGenerateNewRSASSHSessionKeyPair{
			Action:  "Encode Private Key to memory",
			Message: "private key PEM encoded to be nil",
		}, nil
	}
	privateKeyPemStr := string(privateKeyPem)

	// 3. 获取 Public Key PEM
	publicKey := privateKey.PublicKey
	publicKeyDer, err := x509.MarshalPKIXPublicKey(&publicKey)
	if err != nil {
		return errors.ErrGenerateNewRSASSHSessionKeyPair{
			Action:  "Marshal PKIX Public Key",
			Message: err.Error(),
		}, nil
	}
	publicKeyBlock := pem.Block{
		Type:    "PUBLIC KEY",
		Headers: nil,
		Bytes:   publicKeyDer,
	}
	publicKeyPem := pem.EncodeToMemory(&publicKeyBlock)
	if publicKeyPem == nil {
		return errors.ErrGenerateNewRSASSHSessionKeyPair{
			Action:  "Encode Public Key to memory",
			Message: "public key PEM encoded to be nil",
		}, nil
	}
	publicKeyPemStr := string(publicKeyPem)

	// 3. 计算 SSH Public SSH Key，用于 ~/.ssh/authorized_keys
	sshPublicKey, err := ssh.NewPublicKey(&publicKey)
	if err != nil {
		return errors.ErrGenerateNewRSASSHSessionKeyPair{
			Action:  "Calculate SSH Public SSH Key",
			Message: err.Error(),
		}, nil
	}
	sshPublicKeyStr := string(ssh.MarshalAuthorizedKey(sshPublicKey))
	return nil, &vo.GenerateNewRSASSHSessionKeyPairVO{
		PublicKeyPEM:  publicKeyPemStr,
		PrivateKeyPEM: privateKeyPemStr,
		PublicKeySsh:  sshPublicKeyStr,
		KeySize:       strconv.Itoa(setting.Devstar.SSHKeypair.KeySize),
	}
}
